library mobs;

import 'dart:html' as html;
import 'core.dart';
import 'drawing.dart';
import 'maps.dart';

class Monster implements Hashable {
  static int _id = 0;
  final int id;
  var gun; // Circular dependencies? Weak typing!
  int hp = 15;
  Point facing;
  List<Sprite> evolutionTargets;

  Monster(): id = _id++, facing = new Point(1, 0), evolutionTargets = [];

  /// This mob gets injured for h hitpoints. ctx is a core.Context object.
  injure(h, ctx) {
    print("Ouch!");
    hp -= h;
    if (hp < 0) {
      ctx.kill(this);
    }
  }

  /// Replace the mob's sprite with the given one.
  switchSprite(sp) {
    sp.pos = sprite.pos;
    sprite = sp;
  }

  /// Use a weapon.
  fire(ctx) {
    if (gun == null) {
      print("I can't fire, I have no equipment!");
      return;
    }
    var bullet = gun.fire(this, facing);
    if (bullet != null) {
      print("pewpew");
      bullet.sprite.pos = sprite.pos;
      ctx.mobs.add(bullet);
    } else {
      print("pew?");
    }
  }

  get rect => new Rect(sprite.pos,
      new Point(sprite.pos.x + sprite.img.width,
          sprite.pos.y + sprite.img.height));

  get dead => hp <= 0;

  Sprite sprite;
  int speed = 3; // Don't go past 32; will cause issues

  moveTarget(ctx) {
    Point tp = ctx.coord(sprite.pos);
    Point playerTp = ctx.coord(ctx.player.sprite.pos);
    if (ctx.player.dead || tp.dist(playerTp) < 15) {
      for (var p in tp.adjacents()) {
        if (ctx.board[p].passable) {
          //print("map says $p is passable, moving from $tp");
          moveTo(tp, p, ctx.board);
          return;
        }
      }
      return;
    }
    moveTo(tp, ctx.board.aStar(tp, playerTp), ctx.board);
  }

  update(ctx) {
    Board b = ctx.board;
    Point tp = ctx.coord(sprite.pos);
    Point playerTp = ctx.coord(ctx.player.sprite.pos);
    if (!b[tp].passable) {
      throw new Exception("Danger Will Robinson");
    }
    moveTarget(ctx);
    if (ctx.player.dead) {
      return;
    }
    var vp = sprite.pos;
    var pvp = ctx.player.sprite.pos;
    if (gun != null && vp.dist(pvp) < gun.range) {
      var bullet = gun.fire(this,
          new Point.unitRay(vp, pvp));
      if (bullet != null) {
        ctx.mobs.add(bullet);
      }
    }
  }

  moveTo(Point start, Point dest, Board board) {
    // We don't know what these map to, exactly, but we know the relative
    // direction we're going.
    if (dest == null) return;
    if (dest.cornerwiseTo(start)) {
      var c1 = new Point(start.x, dest.y);
      var c2 = new Point(dest.x, start.y);
      if (!board[c1].passable || !board[c2].passable) {
        // only passable if the adjoining cardinals are passable
        return;
      }
    }
    scale(p) => p == 0 ? p : (p / p.abs()).toInt();
    var dx = scale(dest.x - start.x);
    var dy = scale(dest.y - start.y);
    sprite.pos = new Point(sprite.pos.x + dx * speed,
        sprite.pos.y + dy * speed);
    facing = new Point.unitRay(start, dest);
  }

  get hashCode => id;
}